<?php


namespace app\mod\pcr;

use app\mod\pcr\model\PcrGveGroup;
use app\mod\pcr\model\PcrGveGroupFight;
use app\mod\pcr\model\PcrGveGroupMember;
use app\mod\pcr\model\PcrGveGroupStatus;
use app\mod\pcr\service\PcrGveGroupService;
use core\entity\GroupUser;
use core\event\EventGroupMessage;
use core\lib\BotAPI;
use core\Mod;
use utils\PcrUtils;

class GveMod extends Mod {

    /**
     * @var PcrGveGroup
     */
    protected $pcr_group;

    /**
     * @var PcrGveGroupMember
     */
    protected $pcr_group_member;

    /**
     * @var PcrGveGroupService
     */
    protected $gve_group_service;


    public function eventGroupMessage(EventGroupMessage $event) {
        $this->gve_group_service = new PcrGveGroupService();
        $message_format = $event->getMessage()->format();
        if (!isset($message_format[0]['data']['text'])) {
            return;
        }
        $cmd = trim($message_format[0]['data']['text'], ' ');
        $cmd = strtolower(explode(" ", $cmd)[0]);
        static $COMMAND = [
            '#创建公会' => ['createGroup', 'pre' => []],
            '#加入成员' => ['joinMember', 'pre' => ['hasGroup']],
            '#报刀' => ['reportFight', 'pre' => ['hasGroup', 'hasMember', 'has3Attack']],
            '#尾刀' => ['reportEndFight', 'pre' => ['hasGroup', 'hasMember', 'has3Attack']],
            '#挂树' => ['inTree', 'pre' => ['hasGroup', 'hasMember']],
            '#取消挂树' => ['outTree', 'pre' => ['hasGroup', 'hasMember']],
            '#sl' => ['reportSL', 'pre' => ['hasGroup', 'hasMember']],
            '#取消sl' => ['unReportSL', 'pre' => ['hasGroup', 'hasMember']],
            '#申请出刀' => ['applyFight', 'pre' => ['hasGroup', 'hasMember']],
            '#解锁' => ['unlockBoss', 'pre' => ['hasGroup', 'hasMember']],
            '#查树' => ['searchTree', 'pre' => ['hasGroup', 'hasMember']],
            '#撤销' => ['cancelReport', 'pre' => ['hasGroup', 'hasMember']],
            '#催刀' => '',
            '#状态' => ['getStatus', 'pre' => ['hasGroup']],
            '/pcr_gve_initGroupStatus' => ['initGroupStatus', 'pre' => ['hasGroup']],
        ];
        if (!empty($COMMAND[$cmd])) {
            $action = $COMMAND[$cmd][0];
            $pre = $COMMAND[$cmd]['pre'];
            try {
                foreach ($pre as $_pre) {
                    $this->{$_pre}($event);
                }
                $this->{$action}($event);
            } catch (\Exception $e) {
                $event->getGroup()->sendMessage($e->getMessage());
                return;
            }
        }
    }

    protected function cancelReport(EventGroupMessage $event) {
        // 获取最后一条出刀记录
        $report = (new PcrGveGroupFight())->getLastLog($this->pcr_group['id']);
        if ($report['user_id'] !== $event->getSender()->id
            && $event->getSender()->permission < GroupUser::PERMISSION_ADMIN) {

            $event->getGroup()->sendMessage("无权撤销不属于自己的出刀记录。");
            return;
        }
        $this->gve_group_service->cancelReport($report);
        $event->getGroup()->sendMessage("成功撤销："
            . bot()->getGroupMemberInfo($event->getGroup()->id, $report['user_id'])['card']
            . "的对BOSS造成 {$report['attack']} 的出刀记录");
        $this->getStatus($event);
    }

    protected function hasGroup(EventGroupMessage $event) {
        $this->pcr_group = (new PcrGveGroup())->getByQQGroupId($event->getGroup()->id);
        if (is_null($this->pcr_group)) {
            throw new \Exception("当前群未创建公会！");
        }
    }

    protected function hasMember(EventGroupMessage $event) {
        $this->pcr_group_member =
            (new PcrGveGroupMember())->getByGroupUserId($this->pcr_group['id'], $event->getSender()->id);
        if (is_null($this->pcr_group_member)) {
            throw new \Exception("未加入公会！");
        }
    }

    protected function has3Attack(EventGroupMessage $event) {
        $model_fight = new PcrGveGroupFight();
        // 判断当前用户是否已经出满三刀
        // 获得当前日期的开始和结束时间
        $st = PcrUtils::getDayStartAt();
        $ed = PcrUtils::getDayEndAt();
        $reports = $model_fight->getUserReportWithTimeRange($this->pcr_group['id'], $event->getSender()->id
            , $st, $ed, PcrGveGroupFight::TYPE_NORMAL);
        if (count($reports) >= 3) {
            throw new \Exception("今日已满三刀，无法申请或报刀");
        }
    }

    protected function unlockBoss(EventGroupMessage $event) {
        if ($event->getSender()->permission < GroupUser::PERMISSION_ADMIN) {
            return;
        }
        $status = $this->gve_group_service->getGroupStatus($this->pcr_group['id']);
        $status['locked'] = PcrGveGroupStatus::LOCKE_STATUS_UNLOCKED;
        $status['locker_user_id'] = 0;
        $status->save();
        $event->getGroup()->sendMessage("已解锁BOSS，可以申请挑战。");
    }

    protected function applyFight(EventGroupMessage $event) {
        $status = $this->gve_group_service->getGroupStatus($this->pcr_group['id']);
        if ($status['locked'] === PcrGveGroupStatus::LOCKE_STATUS_LOCKED) {
            // 获得锁定人的昵称
            $locker_user_id = $status['locker_user_id'];
            $info = bot()->getGroupMemberInfo($event->getGroup()->id, $locker_user_id);
            if (empty($info)) {
                $event->getGroup()->sendMessage("获取成员 {$locker_user_id} 信息失败！");
                return;
            }
            $event->getGroup()->sendMessage("申请失败！{$this->pcr_group_member['nickname']} 正在挑战BOSS");
            return;
        }
        $status['locked'] = PcrGveGroupStatus::LOCKE_STATUS_LOCKED;
        $status['locker_user_id'] = $event->getSender()->id;
        $nickname = $event->getSender()->nickname;
        $status->save();
        $event->getGroup()->sendMessage("{$nickname}开始挑战BOSS！");
    }

    protected function getStatus(EventGroupMessage $event) {
        $status = $this->gve_group_service->getGroupStatus($this->pcr_group['id']);
        if (empty($status)) {
            $event->getGroup()->sendMessage("获取状态失败，请确认是否正常初始化！");
            return;
        }
        $text = <<<TEXT
当前 {$status['round']} 周目BOSS：{$status['boss_sort_id']} 王
血量剩余：{$status['hp']}
TEXT;
        $event->getGroup()->sendMessage($text);
    }

    protected function initGroupStatus(EventGroupMessage $event) {
        // 判断是否为群主
        if ($event->getSender()->permission < GroupUser::PERMISSION_OWNER) {
            $event->getGroup()->sendMessage("权限不足，无法操作！");
            return;
        }
        // 获得QQ群号的组
        try {
            $this->gve_group_service->initThemeStatus($this->pcr_group['id'], 1);
            $event->getGroup()->sendMessage("成功初始化公会状态！");
        } catch (\Exception $e) {
            $event->getGroup()->sendMessage($e->getMessage());
        }

    }

    protected function createGroup(EventGroupMessage $event) {
        // 判断是否为管理员
        if ($event->getSender()->permission === GroupUser::PERMISSION_MEMBER) {
            return;
        }
        // 判断是否已经存在公会
        $origin = (new PcrGveGroup())->getByQQGroupId($event->getGroup()->id);
        if (!empty($origin)) {
            $event->getGroup()->sendMessage("该群已存在公会！");
            return;
        }
        // 创建公会
        (new PcrGveGroupService())->createGroup($event->getGroup()->id, $event->getSender()->id, '未命名公会');
        $event->getGroup()->sendMessage("公会创建成功！");
    }

    protected function joinMember(EventGroupMessage $event) {
        if ($event->getSender()->permission < GroupUser::PERMISSION_ADMIN) {
            return;
        }
        // 获取所有at
        $message_format = $event->getMessage()->format();
        $user_id = 0;
        foreach ($message_format as $_format) {
            if ($_format['type'] === 'at' && $_format['data']['qq'] !== 'all') {
                $user_id = (int)$_format['data']['qq'];
            }
        }
        // 把成员全部加入公会
        $m = new PcrGveGroupMember();
        $r = $m->getByGroupUserId($this->pcr_group['id'], $event->getSender()->id);
        if (!empty($r)) {
            $event->getGroup()->sendMessage("该成员已加入公会！");
            return;
        }
        $info = bot()->getGroupMemberInfo($event->getGroup()->id, $event->getSender()->id);
        if (empty($info)) {
            $event->getGroup()->sendMessage("获取成员信息失败！");
            return;
        }
        $this->gve_group_service->addMember($this->pcr_group['id'], $user_id, $info['nickname']);
        $event->getGroup()->sendMessage("{$info['nickname']} 加入成功！");
    }

    protected function reportFight(EventGroupMessage $event) {
        // 获得伤害
        $text = $event->getMessage()->string();
        $splits = explode(' ', $text);
        if (count($splits) < 2) {
            return;
        }
        $attack = $splits[1];
        if (!is_numeric($attack) || $attack < 0) {
            return;
        }
        $attack = (int)$attack;
        $status = $this->gve_group_service->getGroupStatus($this->pcr_group['id']);
        if ($attack >= $status['hp']) {
            $event->getGroup()->sendMessage("斩杀BOSS请使用尾刀");
            return;
        }
        $this->gve_group_service
            ->attackBoss($this->pcr_group['id'], $event->getSender()->id, $attack, $status['hp'], PcrGveGroupFight::TYPE_NORMAL);
        // 修改BOSS状态
        $status['hp'] = $status['hp'] - $attack;
        $status['locked'] = PcrGveGroupStatus::LOCKE_STATUS_UNLOCKED;
        $status['locker_user_id'] = 0;
        $status->save();
        // 报刀结果
        $event->getGroup()->sendMessage($event->getSender()->card . "对BOSS造成{$attack}伤害，剩余血量：{$status['hp']}");
    }

    protected function reportEndFight(EventGroupMessage $event) {
        $status = $this->gve_group_service->getGroupStatus($this->pcr_group['id']);
        $hp = $status['hp'];
        $status['locked'] = PcrGveGroupStatus::LOCKE_STATUS_UNLOCKED;
        $status['locker_user_id'] = 0;
        $this->gve_group_service->attackBoss($this->pcr_group['id'], $event->getSender()->id, $hp, $status['hp']
            , PcrGveGroupFight::TYPE_END);
        $this->gve_group_service->nextBoss($this->pcr_group['id']);
        $event->getGroup()->sendMessage("{$event->getSender()->card}对BOSS造成了{$hp}伤害并击杀！");
        // 报告BOSS状态
        $this->getStatus($event);
        // 下树
        $this->allOutTree($event);
    }

    protected function inTree(EventGroupMessage $event) {
        $this->pcr_group_member['flag_tree'] = 1;
        $this->pcr_group_member->save();
        $event->getGroup()->sendMessage('已挂树');
    }

    // BOSS击杀后所有人员下树
    protected function allOutTree(EventGroupMessage $event) {
        $list = (new PcrGveGroupMember())->getListInTheTree($this->pcr_group['id'], $this->pcr_group_member['user_id']);
        if (empty($list)) {
            return;
        }
        $message = "可以下树了！";
        $user_ids = [];
        foreach ($list as $_item) {
            $message .= at($_item['user_id']);
            array_push($user_ids, $_item['user_id']);
        }
        (new PcrGveGroupMember())->where('user_id', 'in', $user_ids)->update([
            'flag_tree' => 0,
        ]);
        if (empty($user_ids)) {
            return;
        }
        $event->getGroup()->sendMessage($message);
    }

    protected function outTree(EventGroupMessage $event) {
        $this->pcr_group_member['flag_tree'] = 0;
        $this->pcr_group_member->save();
        $event->getGroup()->sendMessage('已取消挂树');
    }

    protected function reportSL(EventGroupMessage $event) {
        // 判断之前是否已有SL
        if (!empty($this->pcr_group_member['flag_sl_at'])) {
            $sl_at = $this->pcr_group_member['flag_sl_at'];
            if ($sl_at >= PcrUtils::getDayStartAt() && $sl_at <= PcrUtils::getDayEndAt()) {
                $event->getGroup()->sendMessage("SL失败，今日SL次数已使用！");
                return;
            }
        }
        $this->pcr_group_member['flag_sl_at'] = time();
        $this->pcr_group_member->save();
        $event->getGroup()->sendMessage("已记录SL");
    }

    protected function unReportSL(EventGroupMessage $event) {
        $this->pcr_group_member['flag_sl_at'] = 0;
        $this->pcr_group_member->save();
        $event->getGroup()->sendMessage("已取消SL");
    }

    protected function searchTree(EventGroupMessage $event) {
        $list = (new PcrGveGroupMember())->getListInTheTree($this->pcr_group['id'], $this->pcr_group_member['user_id']);
        $names = [];
        foreach ($list as $_item) {
            array_push($names, $_item['nickname']);
        }
        if (empty($names)) {
            $event->getGroup()->sendMessage("当前没有人在树上");
        } else {
            $event->getGroup()->sendMessage("当前挂树名单：\n" . implode("\n", $names));
        }
    }

}
